﻿using System;
using System.IO;
using System.Linq;
using System.Reflection;

namespace Patterns.Tools.CodeGenerators
{
	public class AppDomainScope : IDisposable
	{
		private readonly AppDomain _domain;

		public AppDomainScope()
		{
			_domain = AppDomain.CreateDomain(Guid.NewGuid().ToString("N"));
			_domain.AssemblyResolve += (sender, args) => FindAssembly(args.Name);
			_domain.TypeResolve += (sender, args) => FindAssembly(args.Name);
		}

		#region IDisposable Members

		public void Dispose()
		{
			AppDomain.Unload(_domain);
		}

		#endregion

		public T CreateRemoteObject<T>() where T : MarshalByRefObject
		{
			return _domain.CreateInstanceAndUnwrap(typeof (T).Assembly.FullName, typeof (T).FullName) as T;
		}

		private static Assembly FindAssembly(string assemblyName)
		{
			string name = new AssemblyName(assemblyName).Name;
			var dir = new DirectoryInfo(Environment.CurrentDirectory);
			FileInfo match = dir.GetFiles(string.Format("{0}.dll", name), SearchOption.AllDirectories).FirstOrDefault();
			return match != null && match.Exists ? Assembly.Load(File.ReadAllBytes(match.FullName)) : null;
		}
	}
}